package com.ddch.tinkerpractise;

import android.app.Activity;
import android.app.Application;
import android.content.BroadcastReceiver;
import android.content.Context;
import android.content.Intent;
import android.content.IntentFilter;
import android.os.Bundle;
import android.os.Handler;
import android.os.Looper;
import android.util.Log;
import android.widget.Toast;

import com.tencent.bugly.Bugly;
import com.tencent.bugly.beta.Beta;
import com.tencent.bugly.beta.interfaces.BetaPatchListener;
import com.tencent.bugly.beta.tinker.TinkerLoadReporter;
import com.tencent.bugly.beta.tinker.TinkerManager;
import com.tencent.bugly.beta.tinker.TinkerPatchListener;
import com.tencent.bugly.beta.tinker.TinkerPatchReporter;
import com.tencent.tinker.lib.patch.UpgradePatch;
import com.tencent.tinker.lib.service.PatchResult;
import com.tencent.tinker.lib.tinker.Tinker;
import com.tencent.tinker.lib.tinker.TinkerLoadResult;
import com.tencent.tinker.lib.util.TinkerLog;
import com.tencent.tinker.lib.util.TinkerServiceInternals;
import com.tencent.tinker.loader.app.DefaultApplicationLike;
import com.tencent.tinker.loader.shareutil.ShareConstants;
import com.tencent.tinker.loader.shareutil.SharePatchFileUtil;

import java.io.File;
import java.util.Locale;

import androidx.annotation.NonNull;
import androidx.annotation.Nullable;
import androidx.multidex.MultiDex;

import static com.tencent.bugly.beta.Beta.betaPatchListener;

/**
 * created by 韦敏敏
 * on 2019/12/2
 */
public class SampleApplicationLike extends DefaultApplicationLike {
    public static final String TAG = "Tinker.SampleApplicationLike";
    private boolean isInstalled = false;
    private boolean isInBg = false;
    private boolean isScreenOn = false;
    private ScreenReceiver mScreenReceiver;
    public SampleApplicationLike(Application application, int tinkerFlags, boolean tinkerLoadVerifyFlag, long applicationStartElapsedTime, long applicationStartMillisTime, Intent tinkerResultIntent) {
        super(application, tinkerFlags, tinkerLoadVerifyFlag, applicationStartElapsedTime, applicationStartMillisTime, tinkerResultIntent);
    }
    @Override
    public void onCreate() {
        super.onCreate();
        getApplication().registerActivityLifecycleCallbacks(new AppLifeCycle());
        init();
    }
    private void init() {
        mScreenReceiver = new ScreenReceiver();
        // 创建IntentFilter对象
        IntentFilter filter = new IntentFilter();
        // 添加要注册的action
        filter.addAction("android.intent.action.SCREEN_OFF");
        filter.addAction("android.intent.action.SCREEN_ON");
        // 动态注册广播接收者
        getApplication().registerReceiver(mScreenReceiver, filter);
        // 设置是否提示用户重启，默认为false
        Beta.canNotifyUserRestart = false;
        // 补丁回调接口
        betaPatchListener = new BetaPatchListener() {
            @Override
            public void onPatchReceived(String patchFile) {
                Log.e("CrashReport","onPatchReceived: "+"补丁下载地址" + patchFile);
            }

            @Override
            public void onDownloadReceived(long savedLength, long totalLength) {
                Log.e("CrashReport","onDownloadReceived: "+"补丁下载地址" + String.format(Locale.getDefault(), "%s %d%%",
                        Beta.strNotificationDownloading,
                        (int) (totalLength == 0 ? 0 : savedLength * 100 / totalLength)));
            }

            @Override
            public void onDownloadSuccess(String msg) {
                Log.e("CrashReport","onDownloadSuccess: "+"补丁下载成功, msg = " + msg);
            }

            @Override
            public void onDownloadFailure(String msg) {
                Log.e("CrashReport","onDownloadFailure: "+"补丁下载失败, msg = " + msg);
            }

            @Override
            public void onApplySuccess(String msg) {
                Log.e("CrashReport","onApplySuccess: "+"补丁应用成功, msg = " + msg);
            }

            @Override
            public void onApplyFailure(String msg) {
                Log.e("CrashReport","onApplyFailure: "+"补丁应用失败, msg = " + msg);
            }

            @Override
            public void onPatchRollback() {
                Log.e("CrashReport","onPatchRollback: "+"补丁应用失败");
            }
        };
        // SDK初始化，appId为在Bugly平台申请的appId
        // 调试时，将第三个参数改为true
        Bugly.init(getApplication(), "44437ff69a", true);
    }

    @Override
    public void onBaseContextAttached(Context base) {
        super.onBaseContextAttached(base);
        MultiDex.install(base);
        // 安装Tinker
        installTinker();
    }
    private void installTinker() {
        // applicationLike, loadReporter, patchReporter, patchListener, tinkerPatchResultListener, upgradePatchProcessor
        TinkerLoadReporter loadReporter = new TinkerLoadReporter(getApplication());
        TinkerPatchReporter patchReporter = new TinkerPatchReporter(getApplication());
        TinkerPatchListener patchListener = new TinkerPatchListener(getApplication());
        UpgradePatch upgradePatch = new UpgradePatch();
        TinkerManager.TinkerPatchResultListener tinkerPatchResultListener = new TinkerManager.TinkerPatchResultListener() {
            @Override
            public void onPatchResult(final PatchResult patchResult) {
                if (patchResult == null) {
                    TinkerLog.e(TAG, "SampleResultService received null result!!!!");
                    return;
                }
                TinkerLog.i(TAG, "SampleResultService receive result: %s", patchResult.toString());
                Log.i("CrashReport", " App - onPatchResult  =  " + patchResult.toString());
                //first, we want to kill the recover process
                TinkerServiceInternals.killTinkerPatchServiceProcess(getApplication());

                Handler handler = new Handler(Looper.getMainLooper());
                handler.post(new Runnable() {
                    @Override
                    public void run() {
                        if (patchResult.isSuccess) {
                            Toast.makeText(getApplication(), "patch success, please restart process", Toast.LENGTH_LONG).show();
                        } else {
                            Toast.makeText(getApplication(), "patch fail, please check reason", Toast.LENGTH_LONG).show();
                        }
                    }
                });
                // is success and newPatch, it is nice to delete the raw file, and restart at once
                // for old patch, you can't delete the patch file
                if (patchResult.isSuccess) {
//                    deleteRawPatchFile(new File(patchResult.rawPatchFilePath));

                    //not like TinkerResultService, I want to restart just when I am at background!
                    //if you have not install tinker this moment, you can use TinkerApplicationHelper api
                    if (checkIfNeedKill(patchResult)) {
                        if (isInBg) {
                            TinkerLog.i(TAG, "it is in background, just restart process");
                            restartProcess();
                            Log.i("CrashReport", " APP inbg -- > it is in background, just restart process");
                        } else {
                            //we can wait process at background, such as onAppBackground
                            //or we can restart when the screen off
                            TinkerLog.i(TAG, "tinker wait screen to restart process");
                            if(!isScreenOn)
                                restartProcess();
                            Log.i("CrashReport", " APP screenOn  -- > it is in background, just restart process : " + isScreenOn);
                        }
                    } else {
                        TinkerLog.i(TAG, "I have already install the newly patch version!");
                    }
                }
            }
        };
        Beta.installTinker(this,loadReporter,patchReporter, patchListener, tinkerPatchResultListener, upgradePatch);
    }

    /**
     * don't delete tinker version file
     * @param rawFile
     */
    public void deleteRawPatchFile(File rawFile) {
        if (!SharePatchFileUtil.isLegalFile(rawFile)) {
            return;
        }
        TinkerLog.w(TAG, "deleteRawPatchFile rawFile path: %s", rawFile.getPath());
        String fileName = rawFile.getName();
        if (!fileName.startsWith(ShareConstants.PATCH_BASE_NAME)
                || !fileName.endsWith(ShareConstants.PATCH_SUFFIX)) {
            SharePatchFileUtil.safeDeleteFile(rawFile);
            return;
        }
        File parentFile = rawFile.getParentFile();
        if (!parentFile.getName().startsWith(ShareConstants.PATCH_BASE_NAME)) {
            SharePatchFileUtil.safeDeleteFile(rawFile);
        } else {
            File grandFile = parentFile.getParentFile();
            if (!grandFile.getName().equals(ShareConstants.PATCH_DIRECTORY_NAME)) {
                SharePatchFileUtil.safeDeleteFile(rawFile);
            }
        }
    }
    public boolean checkIfNeedKill(PatchResult result) {
        Tinker tinker = Tinker.with(getApplication());
        if (tinker.isTinkerLoaded()) {
            TinkerLoadResult tinkerLoadResult = tinker.getTinkerLoadResultIfPresent();
            if (tinkerLoadResult != null) {
                String currentVersion = tinkerLoadResult.currentVersion;
                if (result.patchVersion != null && result.patchVersion.equals(currentVersion)) {
                    return false;
                }
            }
        }
        return true;
    }
    private class AppLifeCycle implements Application.ActivityLifecycleCallbacks{

        @Override
        public void onActivityCreated(@NonNull Activity activity, @Nullable Bundle bundle) {
            isInBg = true;

        }

        @Override
        public void onActivityStarted(@NonNull Activity activity) {
            isInBg = false;
        }

        @Override
        public void onActivityResumed(@NonNull Activity activity) {
            isInBg = false;
        }

        @Override
        public void onActivityPaused(@NonNull Activity activity) {
            isInBg = true;
        }

        @Override
        public void onActivityStopped(@NonNull Activity activity) {
            isInBg = true;
        }

        @Override
        public void onActivitySaveInstanceState(@NonNull Activity activity, @NonNull Bundle bundle) {

        }

        @Override
        public void onActivityDestroyed(@NonNull Activity activity) {
            isInBg = true;
        }
    }
    /**
     * you can restart your process through service or broadcast
     */
    private void restartProcess() {
        TinkerLog.i(TAG, "app is background now, i can kill quietly");
        //you can send service or broadcast intent to restart your process
        final Intent intent = getApplication().getPackageManager().getLaunchIntentForPackage(getApplication().getPackageName());
        intent.addFlags(Intent.FLAG_ACTIVITY_CLEAR_TOP);
        getApplication().startActivity(intent);
        android.os.Process.killProcess(android.os.Process.myPid());
    }
    public class ScreenReceiver extends BroadcastReceiver {
        @Override
        public void onReceive(Context context, Intent intent) {
            // 获取当前广播的事件类型
            String action = intent.getAction();
            if("android.intent.action.SCREEN_OFF".equals(action))
            {
                isScreenOn = false;
                System.out.println("锁屏！");
                Log.e("screen","锁屏");
            }
            else if("android.intent.action.SCREEN_ON".equals(action))
            {
                isScreenOn = true;
                System.out.println("解锁！");
                Log.e("screen","解锁");
            }

        }
    }


}
